using Commons.Collections;
using NVelocity;
using NVelocity.App;
using NVelocity.Runtime;
using System.IO;
using System;
using System.Globalization;
using System.Text;
using ODM2KMZ;
using ODM2KMZ.RSS;

public partial class HIS2RSSStreamer : System.Web.UI.Page
{
 
    private void Page_Load(object sender, System.EventArgs e)
    {
   
 
    }
    private void Page_PreRender(object sender, System.EventArgs e)
    {
    
  
        Response.AppendHeader("Content-Disposition", "inline;filename=HISRSS.xml");
        Response.ContentType = "text/xml";
        if (!onFile()) {
            GetRSSData(); }
         
 }
    private void Page_Unload(object sender, System.EventArgs e)
    {
        
    }

    private bool onFile()
    {
        var filepath = Request.PhysicalPath.Substring(0, Request.PhysicalPath.LastIndexOf("\\"))
               + "\\Cache\\" + Request.QueryString + ".xml";
        try
        {
            if (File.Exists(filepath))
            {
                var dt = File.GetCreationTime(filepath);
                if (dt.AddMinutes(Double.Parse(Request.QueryString["TTL"])) > DateTime.Now)
                {

                    Response.WriteFile(filepath);
                    Response.End();
                    return true;

                }
            }

        }catch
        {
            return false;
        }
        return false;
    }
   
    private  void GetRSSData()
    {
        CultureInfo provider = CultureInfo.CurrentCulture;

        // Create wateroneflow service
        var CurrentService = new WaterOneFlow {Url = Request.QueryString["URL"] };
      
        //Get catalog from waterone flow service
        var siteInfoResponseTypeArray = new SiteInfoResponseType();
        var siteInfoResponseTypeSite = new SiteInfoResponseTypeSite();

        try
        {
            siteInfoResponseTypeArray = CurrentService.GetSiteInfoObject(Request.QueryString["SiteCode"], String.Empty);
            siteInfoResponseTypeSite = siteInfoResponseTypeArray.site[0];
        }
        catch(Exception e)
        {
            throw new Exception("Could not retrieve SiteInfoObject \n" + e.Message);
        }
        //Set up RSS Channel
        var channel = initRSSChannel(siteInfoResponseTypeSite.siteInfo.siteName, Request.QueryString["URL"]);
        double Latitude = ((LatLonPointType)siteInfoResponseTypeSite.siteInfo.geoLocation.geogLocation).latitude;
        double Longitude = ((LatLonPointType)siteInfoResponseTypeSite.siteInfo.geoLocation.geogLocation).longitude;


        channel.point = new point()
                            {
                                crs = "",
                                latitude = Latitude.ToString(),
                                longitude = Longitude.ToString()
                            };

        //Get series catalog
        seriesCatalogTypeSeries[] SeriesCatalogTypeSeries = siteInfoResponseTypeSite.seriesCatalog[0].series;


        //Get date offset
        int intDateOffset = 0;
        if (Request.QueryString["NDAYS"] != null)
        {
            try
            {
                intDateOffset = int.Parse(Request.QueryString["NDAYS"]);
            }
            catch
            {
                intDateOffset = 1;  
            }
        }


        //For each series in the catalog
        foreach (seriesCatalogTypeSeries series in SeriesCatalogTypeSeries)
        {
            //Get series start and end date
            var tuP = (TimeIntervalType) series.variableTimeInterval;

            //Set start date to be enddate - NDays
            DateTime StartDate = tuP.endDateTime.AddDays(-intDateOffset);


            TimeSeriesResponseType Data = CurrentService.GetValuesObject(
                Request.QueryString["SiteCode"], series.variable.variableCode[0].vocabulary + ":" +
                                                 series.variable.variableCode[0].Value, StartDate.ToString("s"),
                tuP.endDateTime.ToString("s"),
                string.Empty);

            // Create RSS Item
            var item = createRSSItem(series, Data);
            var displayData = "FALSE";
            if (Request.QueryString["DISPLAY_NO_DATA"] != null)
            {
                displayData = Request.QueryString["DISPLAY_NO_DATA"];
            }
      

            if (displayData.ToUpper() == "TRUE")   channel.items.Add(item);
         
            else if (item.description != "This variable has no data")
                channel.items.Add(item);

        }

        if (channel.items.Count > 0)
        {
           
            Response.ContentType = "text/xml";
            var template = generateTemplate(channel);
            Response.Write(template);
            
            
            var filepath = Request.PhysicalPath.Substring(0, Request.PhysicalPath.LastIndexOf("\\"))
                           + "\\Cache\\"  +Request.QueryString + ".xml";


            var sw = new StreamWriter(filepath);
            sw.Write(template);
            
            sw.Flush();
            sw.Close();


            Response.End();
        }
        else
        {
            throw new Exception("No variables have data \n");
        }

        return ;
    }

    private item createRSSItem(seriesCatalogTypeSeries series,TimeSeriesResponseType Data)
    {

        var item = new item();
        item.title = "Latest values for " + "VariableCode " +
            series.variable.variableName + " " +
                        series.variable.variableCode[0].Value +
                      " with units of " + Data.timeSeries.values.unitsAbbreviation;
        item.description = "This variable has no data";
        item.pubDate = DateTime.Now.ToUniversalTime();
        item.guid = Guid.NewGuid().ToString();

        var sw = new StringWriter();
        StringBuilder sb = sw.GetStringBuilder();

        try
        {
            var vsv = Data.timeSeries.values.value[Data.timeSeries.values.value.Length-1];
            sb.AppendLine( vsv.Value + " " + Data.timeSeries.values.unitsAbbreviation + " at " + vsv.dateTime.ToString("s"));


            decimal min = 1000000, max = -1000000;
            var lblMax = new GoogleChartLabel(){color = "FFFFFF", labelValue = "Max" , labelType = LabelType.f };
            var lblMin = new GoogleChartLabel() {color = "FF0000", labelValue = "Min", labelType = LabelType.f};
           
            string chartdata = string.Empty;
            int lowerBound = 0;
            if ((Data.timeSeries.values.value.GetUpperBound(0) - 100) >= 0)
            {
                lowerBound = Data.timeSeries.values.value.GetUpperBound(0) - 100;
            }

            for (int i = lowerBound; i <= Data.timeSeries.values.value.GetUpperBound(0); i++)
            {
                 vsv = Data.timeSeries.values.value[i];

                //sb.AppendLine(vsv.dateTime.ToString("s") + " with a value of " +
                //              vsv.Value + " " + Data.timeSeries.values.unitsAbbreviation + "<br/>");
                chartdata += vsv.Value + ",";
                if ( vsv.Value > max)
                {

                    max = vsv.Value;
                    lblMax.labelValue = max.ToString();
                    lblMax.dataPoint = i;
                }
                else if (vsv.Value < min)
                {
                    min = vsv.Value;
                    lblMin.labelValue = min.ToString();
                    lblMin.dataPoint = i;
                }

         

            }
            //Get rid of last comma
            chartdata = chartdata.Substring(0, chartdata.Length - 1);


            var chm = "&chm=" + lblMax.getPointLabel() + "|" + lblMin.getPointLabel();

            //int[] range = CalcRange(max, min);

            var chxt = "&chxt=y&chxr=0," + min + "," + max;
            var chds = "&chds=" + min + "," + max;
            var ChartUrl =
                new Uri("http://chart.apis.google.com/chart?chs=200x50&chd=t:" + chartdata + chds + "&cht=lc"  + chxt);
            sb.Append(@"<img src=" + ChartUrl + " >");
        }
        catch(Exception e)
        {
            return item;
        }

        item.description =  Server.HtmlEncode( sb.ToString());
        //item.description = "Test Description";


        return item;
    }

    private Channel initRSSChannel(string siteName, string url)
    {
        var channel = new Channel()
        {
            title = siteName + " HIS RSS Feeder",
            description = "HIS RSS feed for " +
                siteName + " Latest values",
            link = url
        };

        if (Request.QueryString["TTL"] != null)
        {
            try
            {
                channel.ttl = Request.QueryString["TTL"];
            }
            catch
            {
                channel.ttl = "60"; 
            }
        }
        
        channel.language = "en-us";
        channel.lastBuildDate = DateTime.UtcNow;
        channel.feedURL = Server.HtmlEncode(Request.Url.OriginalString);
       

        return channel;
    }

    public int[] CalcRange(decimal max, decimal min)
    {
        var range = new int[2];
        var minx = (int) Math.Floor(Math.Log10(double.Parse(min.ToString())));
        var miny = (int)Math.Ceiling(Math.Log10(double.Parse(min.ToString())));
        range[0] = (int) Math.Round(min, minx);
        range[1] = (int)Math.Round(min, miny);

        return range;

    }

    public void Page_Error(object sender, EventArgs e)
    {
        Exception objErr = Server.GetLastError().GetBaseException();
        Session["lastError"] = objErr.Message;
        Response.Redirect("ErrorHandler.aspx");
        Server.ClearError();
    }

    private string generateTemplate(Channel channel)
    {
        var ep = new ExtendedProperties();
        ep.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, Request.PhysicalApplicationPath + "templates");

        var ve = new VelocityEngine(ep);
        ve.Init();

        var myTemplate = ve.GetTemplate("Rss20.vm");


        var context = new VelocityContext();
        context.Put("channel", channel);
        context.Put("items", channel.items);


        var sw = new StringWriter();

        myTemplate.Merge(context, sw);


        return sw.ToString();
    }
}
